#pragma once
#include <intrin.h>

bool GetSSEflg();
bool GetAVSflg();
bool GetAVS512();
void PrintInfo();


const __m256i K_INV_ZERO = _mm256_set1_epi8(255);
const __m256i K_ZERO = _mm256_set1_epi8(0);
const __m256i K8_01 = _mm256_set1_epi8(0x01);
const __m128i K_ZEROSSE = _mm_set1_epi8(0);
const __m128i K_INV_ZEROSSE = _mm_set1_epi8(255);
const __m256i K8_01_FF = {  0x01, 0xFF, 0x01, 0xFF, 
							0x01, 0xFF, 0x01, 0xFF, 
							0x01, 0xFF, 0x01, 0xFF, 
							0x01, 0xFF, 0x01, 0xFF, 
							0x01, 0xFF, 0x01, 0xFF, 
							0x01, 0xFF, 0x01, 0xFF, 
							0x01, 0xFF, 0x01, 0xFF, 
							0x01, 0xFF, 0x01, 0xFF };
const __m256i K16_0001 = _mm256_set1_epi16(0x0001);
const __m256i K16_00FF = _mm256_set1_epi16(0x00FF);


//获取整数部分
__forceinline size_t AlignLo(size_t size, size_t align)
{
	return size & ~(align - 1);
}
__forceinline size_t AlignHi(size_t size, size_t align)
{
	return (size + align - 1) & ~(align - 1);
}

//_mm256_extractf128_si256   选择高低位


__forceinline __m256i Correlation(__m256i a, __m256i b)
{
	const __m256i lo = _mm256_madd_epi16(_mm256_unpacklo_epi8(a, _mm256_setzero_si256()), _mm256_unpacklo_epi8(b, _mm256_setzero_si256()));
	const __m256i hi = _mm256_madd_epi16(_mm256_unpackhi_epi8(a, _mm256_setzero_si256()), _mm256_unpackhi_epi8(b, _mm256_setzero_si256()));
	return _mm256_add_epi32(lo, hi);
}
__forceinline __m256i NotEqual8u(__m256i a, __m256i b)
{
	return _mm256_andnot_si256(_mm256_cmpeq_epi8(a, b), K_INV_ZERO);
}

__forceinline __m256i Greater8u(__m256i a, __m256i b)
{
	return _mm256_andnot_si256(_mm256_cmpeq_epi8(_mm256_min_epu8(a, b), a), K_INV_ZERO);
}

__forceinline __m256i GreaterOrEqual8u(__m256i a, __m256i b)
{
	return _mm256_cmpeq_epi8(_mm256_max_epu8(a, b), a);
}

__forceinline __m256i Lesser8u(__m256i a, __m256i b)
{
	return _mm256_andnot_si256(_mm256_cmpeq_epi8(_mm256_max_epu8(a, b), a), K_INV_ZERO);
}

__forceinline __m256i LesserOrEqual8u(__m256i a, __m256i b)
{
	return _mm256_cmpeq_epi8(_mm256_min_epu8(a, b), a);
}


__forceinline __m256i NotEqual16i(__m256i a, __m256i b)
{
	return _mm256_andnot_si256(_mm256_cmpeq_epi16(a, b), K_INV_ZERO);
}

__forceinline __m256i GreaterOrEqual16i_m256(__m256i a, __m256i b)
{
	return _mm256_andnot_si256(_mm256_cmpgt_epi16(b, a), K_INV_ZERO);
}

__forceinline __m256i LesserOrEqual16i(__m256i a, __m256i b)
{
	return _mm256_andnot_si256(_mm256_cmpgt_epi16(a, b), K_INV_ZERO);
}

__forceinline __m256i LoadPermuted(const __m256i* p)
{
	return _mm256_permute4x64_epi64(_mm256_load_si256(p), 0xD8);
}
__forceinline __m256i PackI32ToI16(__m256i lo, __m256i hi)
{
	return _mm256_permute4x64_epi64(_mm256_packs_epi32(lo, hi), 0xD8);
}
__forceinline __m128i CvtPsToEpi8(__m256 valh, __m256 vall)
{	
	__m256i tmp = _mm256_permute4x64_epi64(_mm256_packs_epi32(_mm256_cvtps_epi32(vall), _mm256_cvtps_epi32(valh)), 0xD8);
	return _mm256_castsi256_si128(_mm256_permute4x64_epi64(_mm256_packus_epi16(tmp, tmp), 0xD8));
}


__forceinline __m256i PackI16ToI8(__m256i lo, __m256i hi)
{
	return _mm256_permute4x64_epi64(_mm256_packs_epi16(lo, hi), 0xD8);
}
__forceinline __m256i PackI16ToU8(__m256i lo, __m256i hi)
{
	return _mm256_permute4x64_epi64(_mm256_packus_epi16(lo, hi), 0xD8);
}
__forceinline __m256i CompareSum(const uint32_t* sum, const __m256i& ff_threshold)
{
	const __m256i mask0 = _mm256_cmpgt_epi32(_mm256_madd_epi16(_mm256_loadu_si256((__m256i*)sum + 0), ff_threshold), K_ZERO);
	const __m256i mask1 = _mm256_cmpgt_epi32(_mm256_madd_epi16(_mm256_loadu_si256((__m256i*)sum + 1), ff_threshold), K_ZERO);
	const __m256i mask2 = _mm256_cmpgt_epi32(_mm256_madd_epi16(_mm256_loadu_si256((__m256i*)sum + 2), ff_threshold), K_ZERO);
	const __m256i mask3 = _mm256_cmpgt_epi32(_mm256_madd_epi16(_mm256_loadu_si256((__m256i*)sum + 3), ff_threshold), K_ZERO);
	return PackI16ToI8(PackI32ToI16(mask0, mask1), PackI32ToI16(mask2, mask3));
}

__forceinline __m256i HorizontalSum32(__m256i a)//求整个向量之和 256
{
	return _mm256_add_epi64(_mm256_unpacklo_epi32(a, K_ZERO), _mm256_unpackhi_epi32(a, K_ZERO));
}
__forceinline __m128i HorizontalSum32SSE(__m128i a)//求整个向量之和 128
{
	return _mm_add_epi64(_mm_unpacklo_epi32(a, K_ZEROSSE), _mm_unpackhi_epi32(a, K_ZEROSSE));
}
__forceinline __m256i Square8u(__m256i src) //256求平方和
{
	const __m256i lo = _mm256_unpacklo_epi8(src, _mm256_setzero_si256());
	const __m256i hi = _mm256_unpackhi_epi8(src, _mm256_setzero_si256());
	return _mm256_add_epi32(_mm256_madd_epi16(lo, lo), _mm256_madd_epi16(hi, hi));
}
template <class T> __forceinline __m256i SetMask(T first, size_t position, T second)
{
	const size_t size = 32 / sizeof(T);
	assert(position <= size);
	T mask[size];
	for (size_t i = 0; i < position; ++i)
		mask[i] = first;
	for (size_t i = position; i < size; ++i)
		mask[i] = second;
	return _mm256_loadu_si256((__m256i*)mask);
}
